package com.zp.business.impl.clinicOrder;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.zp.base.api.RemoteClinicItemDictService;
import com.zp.base.api.vo.ClinicItemDictVo;
import com.zp.base.api.vo.PriceListVo;
import com.zp.business.entity.clinicOrder.ClinicOrdersCost;
import com.zp.business.entity.clinicOrder.bo.ApplyItemBo;
import com.zp.business.entity.clinicOrder.bo.ClinicOrdersBo;
import com.zp.business.entity.clinicOrder.bo.ClinicOrdersCostBo;
import com.zp.business.entity.clinicOrder.vo.ClinicOrdersCostVo;
import com.zp.business.entity.clinicOrder.vo.ClinicOrdersVo;
import com.zp.business.mapper.clinicOrder.ClinicOrdersCostMapper;
import com.zp.business.mapper.clinicOrder.ClinicOrdersMapper;
import com.zp.business.service.clinicOrder.IClinicOrdersCostService;
import com.zp.common.core.constant.BaseConstants;
import com.zp.common.core.constant.CacheNames;
import com.zp.common.core.constant.UserConstants;
import com.zp.common.core.utils.StringUtils;
import com.zp.common.myBatis.core.page.PageQuery;
import com.zp.common.myBatis.core.page.TableDataInfo;
import com.zp.common.redis.utils.CacheUtils;
import com.zp.common.satoken.utils.LoginHelper;
import com.zp.system.api.entity.SysDictData;
import lombok.RequiredArgsConstructor;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 门诊项目明细Service业务层处理
 *
 * @author zhang peng
 * @ date 2024-01-05
 */
@RequiredArgsConstructor
@Service
public class ClinicOrdersCostServiceImpl implements IClinicOrdersCostService {

    private final ClinicOrdersCostMapper baseMapper;

    private final ClinicOrdersMapper clinicOrdersMapper;

    @DubboReference
    private RemoteClinicItemDictService remoteClinicItemDictService;

    // 规格单位
    static List<SysDictData> specUnit = CacheUtils.get(CacheNames.SYS_DICT, CacheNames.SPEC_UNIT);


    /**
     * 查询门诊项目明细
     */
    @Override
    public ClinicOrdersCostVo queryById(String id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询门诊项目明细列表(分页)
     */
    @Override
    public TableDataInfo<ClinicOrdersCostVo> queryPageList(ClinicOrdersCostBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<ClinicOrdersCost> lqw = buildQueryWrapper(bo);
        Page<ClinicOrdersCostVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询门诊项目明细列表(不分页)
     */
    @Override
    public List<ClinicOrdersCostVo> queryList(ClinicOrdersCostBo bo) {
        ClinicOrdersBo clinicOrdersBo = new ClinicOrdersBo();
        clinicOrdersBo.setOrdersIdArray(bo.getOrdersIdArray());
        // 获取clinic_orders信息
        List<ClinicOrdersVo> clinicOrdersVos = clinicOrdersMapper.selectVoInOrdersIdArray(clinicOrdersBo);
        LambdaQueryWrapper<ClinicOrdersCost> lqw = buildQueryWrapper(bo);
        // 获取clinic_order_cost信息
        List<ClinicOrdersCostVo> clinicOrdersCostVos = baseMapper.selectVoList(lqw);
        clinicOrdersCostVos.forEach(item -> {
            List<ClinicOrdersVo> collect = clinicOrdersVos.stream().filter(e -> StringUtils.equals(e.getId(), item.getOrdersId())).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(collect)) {
                item.setApplyNo(collect.get(0).getApplyNo());
            }
            List<SysDictData> SysDictDataList = specUnit.stream()
                    .filter(i -> StringUtils.equals(item.getUnit(), i.getDictValue())).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(SysDictDataList)) {
                if (StringUtils.equals(item.getUnit(), SysDictDataList.get(0).getDictValue())) {
                    item.setUnitName(SysDictDataList.get(0).getDictLabel());
                } else {
                    item.setUnitName(item.getUnit());
                }
            } else {
                item.setUnitName(item.getUnit());
            }
        });
        return clinicOrdersCostVos;
    }

    private LambdaQueryWrapper<ClinicOrdersCost> buildQueryWrapper(ClinicOrdersCostBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<ClinicOrdersCost> lqw = Wrappers.lambdaQuery();
        lqw.in(CollectionUtil.isNotEmpty(bo.getOrdersIdArray()), ClinicOrdersCost::getOrdersId, bo.getOrdersIdArray());
        lqw.eq(StringUtils.isNotBlank(bo.getClinicId()), ClinicOrdersCost::getClinicId, bo.getClinicId());
        lqw.eq(StringUtils.isNotBlank(bo.getPatientId()), ClinicOrdersCost::getPatientId, bo.getPatientId());
        lqw.eq(StringUtils.isNotBlank(bo.getOrdersId()), ClinicOrdersCost::getOrdersId, bo.getOrdersId());
        lqw.eq(StringUtils.isNotBlank(bo.getItemClass()), ClinicOrdersCost::getItemClass, bo.getItemClass());
        lqw.like(StringUtils.isNotBlank(bo.getPackItemName()), ClinicOrdersCost::getPackItemName, bo.getPackItemName());
        lqw.like(StringUtils.isNotBlank(bo.getItemName()), ClinicOrdersCost::getItemName, bo.getItemName());
        lqw.eq(StringUtils.isNotBlank(bo.getItemCode()), ClinicOrdersCost::getItemCode, bo.getItemCode());
        lqw.eq(StringUtils.isNotBlank(bo.getPriceId()), ClinicOrdersCost::getPriceId, bo.getPriceId());
        lqw.eq(bo.getNetworkPrice() != null, ClinicOrdersCost::getNetworkPrice, bo.getNetworkPrice());
        lqw.eq(bo.getTradePrice() != null, ClinicOrdersCost::getTradePrice, bo.getTradePrice());
        lqw.eq(bo.getPrice() != null, ClinicOrdersCost::getPrice, bo.getPrice());
        lqw.eq(bo.getCosts() != null, ClinicOrdersCost::getCosts, bo.getCosts());
        lqw.eq(bo.getCharges() != null, ClinicOrdersCost::getCharges, bo.getCharges());
        lqw.eq(bo.getDiffCost() != null, ClinicOrdersCost::getDiffCost, bo.getDiffCost());
        lqw.eq(bo.getNum() != null, ClinicOrdersCost::getNum, bo.getNum());
        lqw.eq(bo.getMedicalScale() != null, ClinicOrdersCost::getMedicalScale, bo.getMedicalScale());
        lqw.eq(StringUtils.isNotBlank(bo.getFeesNo()), ClinicOrdersCost::getFeesNo, bo.getFeesNo());
        lqw.eq(StringUtils.isNotBlank(bo.getClassOnRcpt()), ClinicOrdersCost::getClassOnRcpt, bo.getClassOnRcpt());
        lqw.eq(StringUtils.isNotBlank(bo.getClassOnReckoning()), ClinicOrdersCost::getClassOnReckoning, bo.getClassOnReckoning());
        lqw.eq(StringUtils.isNotBlank(bo.getSubjCode()), ClinicOrdersCost::getSubjCode, bo.getSubjCode());
        lqw.eq(bo.getCoefficient() != null, ClinicOrdersCost::getCoefficient, bo.getCoefficient());
        lqw.eq(StringUtils.isNotBlank(bo.getSpec()), ClinicOrdersCost::getSpec, bo.getSpec());
        lqw.eq(StringUtils.isNotBlank(bo.getUnit()), ClinicOrdersCost::getUnit, bo.getUnit());
        lqw.eq(StringUtils.isNotBlank(bo.getOrgId()), ClinicOrdersCost::getOrgId, bo.getOrgId());
        lqw.eq(bo.getAbidance() != null, ClinicOrdersCost::getAbidance, bo.getAbidance());
        lqw.like(StringUtils.isNotBlank(bo.getChannel()), ClinicOrdersCost::getChannel, bo.getChannel());
        lqw.like(StringUtils.isNotBlank(bo.getPerformFreq()), ClinicOrdersCost::getPerformFreq, bo.getPerformFreq());
        lqw.eq(bo.getSingleDosage() != null, ClinicOrdersCost::getSingleDosage, bo.getSingleDosage());
        lqw.like(StringUtils.isNotBlank(bo.getSingleUnitName()), ClinicOrdersCost::getSingleUnitName, bo.getSingleUnitName());
        lqw.eq(StringUtils.isNotBlank(bo.getMedicalVerifyFlag()), ClinicOrdersCost::getMedicalVerifyFlag, bo.getMedicalVerifyFlag());
        lqw.eq(StringUtils.isNotBlank(bo.getMedicalVerifyPerson()), ClinicOrdersCost::getMedicalVerifyPerson, bo.getMedicalVerifyPerson());
        lqw.eq(bo.getMedicalVerifyDate() != null, ClinicOrdersCost::getMedicalVerifyDate, bo.getMedicalVerifyDate());
        lqw.eq(StringUtils.isNotBlank(bo.getRemarks()), ClinicOrdersCost::getRemarks, bo.getRemarks());
        lqw.eq(StringUtils.isNotBlank(bo.getIsUpload()), ClinicOrdersCost::getIsUpload, bo.getIsUpload());
        lqw.orderByAsc(ClinicOrdersCost::getOrdersId).orderByAsc(ClinicOrdersCost::getCreateTime);
        return lqw;
    }

    /**
     * 新增门诊项目明细
     */
    @Override
    public Boolean insertByBo(ClinicOrdersCostBo bo) {
        ClinicOrdersCost add = BeanUtil.toBean(bo, ClinicOrdersCost.class);
        validEntityBeforeSave(add);
        add.initEntity();
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改门诊项目明细
     */
    @Override
    public Boolean updateByBo(ClinicOrdersCostBo bo) {
        ClinicOrdersCost update = BeanUtil.toBean(bo, ClinicOrdersCost.class);
        update.setUpdateBy(LoginHelper.getUserId());
        update.setUpdateTime(new Date());
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(ClinicOrdersCost entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除门诊项目明细
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<String> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public Map<String, Object> saveByBo(ClinicOrdersBo bo, List<ApplyItemBo> applyItemBoList, int num) {
        Map<String, Object> map = new HashMap<String, Object>();
        boolean b = false;
        // 应收
        BigDecimal amount = new BigDecimal(BigInteger.ZERO);
        // 实收
        BigDecimal paidUpAmount = new BigDecimal(BigInteger.ZERO);
        // 附加项目类型
        String whetherToComeInAttachedItemClass = "";
        //TODO 存在循环中查询数据库，待优化
        for (ApplyItemBo applyItemBo : applyItemBoList) {
            // 获取诊疗项目所有价表项目
            List<ClinicItemDictVo> clinicItemsAndPriceList = remoteClinicItemDictService.getClinicItemsAndPriceList(
                    bo.getOrgId(), new ArrayList<>(), Collections.singletonList(applyItemBo.getClinicItemId()));
            for (ClinicItemDictVo clinicItemsAndPrice : clinicItemsAndPriceList) {
                if (StringUtils.equals(bo.getWhetherToComeInAttached(), UserConstants.YES)) {
                    whetherToComeInAttachedItemClass = clinicItemsAndPrice.getItemClass();
                }
                List<PriceListVo> priceList = clinicItemsAndPrice.getPriceListVoList();
                if (CollectionUtil.isEmpty(priceList)) {
                    throw new RuntimeException("项目：" + clinicItemsAndPrice.getItemName() + "没有进行项目对照,请联系管理员后增加对照后再收费");
                }
                List<ClinicOrdersCost> clinicOrdersCostList = new ArrayList<>();
                for (PriceListVo item : priceList) {
                    ClinicOrdersCost clinicOrdersCost = new ClinicOrdersCost();
                    clinicOrdersCost.setConfirmFlag(BaseConstants.CONFIRM_FLAG.UNISSUED);
                    clinicOrdersCost.setApplyNo(bo.getApplyNo());
                    clinicOrdersCost.setChargeFlag(bo.getChargeFlag());
                    clinicOrdersCost.setClinicId(bo.getClinicId());
                    clinicOrdersCost.setPatientId(bo.getPatientId());
                    clinicOrdersCost.setOrgId(bo.getOrgId());
                    clinicOrdersCost.setOrdersId(bo.getId());
                    clinicOrdersCost.setItemClass(item.getItemClass());
                    clinicOrdersCost.setItemCode(item.getItemCode());
                    clinicOrdersCost.setPackItemName(clinicItemsAndPrice.getItemName());
                    clinicOrdersCost.setItemName(item.getItemName());
                    clinicOrdersCost.setPriceId(item.getPriceId());
                    clinicOrdersCost.setTradePrice(item.getTradePrice());
                    clinicOrdersCost.setNetworkPrice(item.getNetworkPrice());
                    clinicOrdersCost.setPrice(item.getPrice());
                    // 总数量 = 价标对照中的数量 * 前台页面出入的数量
                    clinicOrdersCost.setNum(item.getClinicVsPriceVo().getAmount() * applyItemBo.getNum() * num);
                    clinicOrdersCost.setCosts(item.getPrice().multiply(BigDecimal.valueOf(clinicOrdersCost.getNum())));
                    clinicOrdersCost.setCoefficient(BigDecimal.ONE);
                    // 应收 * 收费系数 = 实收
                    clinicOrdersCost.setCharges(clinicOrdersCost.getCosts().multiply(clinicOrdersCost.getCoefficient()));
                    clinicOrdersCost.setSpec(item.getItemSpec());
                    clinicOrdersCost.setUnit(item.getUnits());
                    clinicOrdersCost.setSingleDosage(BigDecimal.valueOf(1));
                    clinicOrdersCost.setClassOnRcpt(item.getClassOnRcpt());
                    clinicOrdersCost.setIsUpload(bo.getIsUpload());
                    clinicOrdersCost.setClassOnReckoning(item.getClassOnReckoning());
                    clinicOrdersCost.setSubjCode(item.getSubjCode());
                    clinicOrdersCost.initEntity();
                    amount = amount.add(clinicOrdersCost.getCosts());
                    paidUpAmount = paidUpAmount.add(clinicOrdersCost.getCharges());
                    // 设置业务明细id
                    clinicOrdersCost.setApplyItemId(applyItemBo.getApplyItemId());
                    clinicOrdersCost.setClinicItemId(applyItemBo.getClinicItemId());
                    clinicOrdersCostList.add(clinicOrdersCost);
                }
                b = baseMapper.insertBatch(clinicOrdersCostList);
            }
        }


        map.put("flag", b);
        map.put("costs", amount);
        // 实收
        map.put("paidUpAmount", paidUpAmount);
        map.put("whetherToComeInAttachedItemClass", whetherToComeInAttachedItemClass);
        return map;
    }

    @Override
    @Transactional
    public Boolean deleteInOrderId(String clinicOrdersId) {
        Map<String, Object> columnMap = new HashMap<String, Object>();
        columnMap.put("orders_id", clinicOrdersId);
        return baseMapper.deleteByMap(columnMap) > 0;
    }

    @Override
    public Boolean saveBatch(List<ClinicOrdersCost> list) {
        return baseMapper.insertBatch(list);
    }


    /**
     * 修改收费状态
     *
     * @param chargeType            收费状态
     * @param clinicOrderIdOrCostId 门诊医嘱id或者costId
     * @return
     */
    @Override
    public Boolean updateChargeType(String chargeType, String clinicOrderIdOrCostId, String type) {
        return baseMapper.update(null, new LambdaUpdateWrapper<ClinicOrdersCost>()
                .set(ClinicOrdersCost::getChargeFlag, chargeType)
                .eq(StringUtils.equals(type, BaseConstants.ITEM_REFUND_OR_CANCEL.ALL), ClinicOrdersCost::getOrdersId, clinicOrderIdOrCostId)
                .eq(StringUtils.equals(type, BaseConstants.ITEM_REFUND_OR_CANCEL.SINGLE), ClinicOrdersCost::getApplyItemId, clinicOrderIdOrCostId)
        ) > 0;
    }
}
